home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / haeberli / libgutil / track.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  8KB  |  356 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /* 
  18.  *    track -
  19.  *        Simple track ball interface
  20.  *    
  21.  *            Originally by Gavin Bell
  22.  *            Rehacked by Paul Haeberli
  23.  *    exports:
  24.  *        trackclick();
  25.  *        trackpoll();
  26.  *        tracktransform();
  27.  *
  28.  */
  29. #include "gl.h"
  30. #include "device.h"
  31. #include "math.h"
  32. #include "vect.h"
  33.  
  34. static tinit();
  35.  
  36. #define SQRT2        1.41421356237309504880
  37. #define SQRT1_2        0.70710678118654752440
  38.  
  39. static vect trans;
  40. static float rvec[4];
  41. static float spinrot[4];
  42. static int firsted;
  43. static int omx, omy;
  44.  
  45. trackclick()
  46. {
  47.     omx = getvaluator(MOUSEX);
  48.     omy = getvaluator(MOUSEY);
  49. }
  50.  
  51. trackpoll()
  52. {
  53.     int mstate;
  54.     int mx, my;
  55.     int dx, dy, del;
  56.     long xorg, yorg;
  57.     long xsize, ysize;
  58.     float x1, y1, x2, y2;
  59.     float r[4];
  60.  
  61.     if(!firsted) {
  62.     tinit();
  63.     firsted = 1;
  64.     }
  65.     getorigin(&xorg,&yorg);
  66.     getsize(&xsize,&ysize);
  67.     mstate = 0;
  68.     if(getbutton(MIDDLEMOUSE)) 
  69.     mstate |= 1;
  70.     if(getbutton(LEFTMOUSE)) 
  71.     mstate |= 2;
  72.     mx = getvaluator(MOUSEX);
  73.     my = getvaluator(MOUSEY);
  74.     dx = mx-omx;
  75.     dy = my-omy;
  76.     switch(mstate) {
  77.     case 0:
  78.         break;
  79.     case 1:
  80.         trans.x += (float)dx/xsize;
  81.         trans.y += (float)dy/xsize;
  82.         break;
  83.     case 2:
  84.         x1 = (2.0*(float)(omx-xorg)/xsize)-1.0;
  85.         y1 = (2.0*(float)(omy-yorg)/ysize)-1.0;
  86.         x2 = (2.0*(float)( mx-xorg)/xsize)-1.0;
  87.         y2 = (2.0*(float)( my-yorg)/ysize)-1.0;
  88.         trackball(r,x1,y1,x2,y2);
  89.             spinrot[0] = r[0];
  90.             spinrot[1] = r[1];
  91.             spinrot[2] = r[2];
  92.             spinrot[3] = r[3];
  93.         break;
  94.     case 3:
  95.         del = dx+dy;
  96.         trans.z += 4.0*(float)del/xsize;
  97.         break;
  98.     }
  99.     omx = mx;
  100.     omy = my;
  101. }
  102.  
  103. gettracktransform(mat)
  104. float mat[4][4];
  105. {
  106.     if(!firsted) {
  107.     tinit();
  108.     firsted = 1;
  109.     }
  110.     add_quats(spinrot,rvec,rvec);
  111.     pushmatrix();
  112.     myidentity();
  113.     translate(trans.x,trans.y,trans.z);
  114.     build_rotmatrix(mat,rvec);
  115.     multmatrix(mat);
  116.     getmatrix(mat);
  117.     popmatrix();
  118. }
  119.  
  120. tracktransform()
  121. {
  122.     float m[4][4];
  123.  
  124.     gettracktransform(m);
  125.     multmatrix(m);
  126. }
  127.  
  128. trackztrans(z)
  129. float z;
  130. {
  131.     if(!firsted) {
  132.     tinit();
  133.     firsted = 1;
  134.     }
  135.     trans.z = z;
  136. }
  137.  
  138. static tinit()
  139. {
  140.     vset(&trans,0.0,0.0,0.0);
  141.     rvec[0] = 0.00;
  142.     rvec[1] = 0.00;
  143.     rvec[2] = 0.00;
  144.     rvec[3] = 1.00;
  145.     trackball(spinrot,0.0,-0.1,0.01,-0.1);
  146. }
  147.  
  148. /*
  149.  *    Implementation of a virtual trackball.
  150.  *    Implemented by Gavin Bell, lots of ideas from Thant Tessman and
  151.  *        the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
  152.  *
  153.  */
  154. #define RENORMCOUNT 97
  155. /*
  156.  * This size should really be based on the distance from the center of
  157.  * rotation to the point on the object underneath the mouse.  That
  158.  * point would then track the mouse as closely as possible.  This is a
  159.  * simple example, though, so that is left as an Exercise for the
  160.  * Programmer.
  161.  */
  162. #define TRACKBALLSIZE  (0.8)
  163.  
  164. float tb_project_to_sphere();
  165.  
  166. /*
  167.  * Ok, simulate a track-ball.  Project the points onto the virtual
  168.  * trackball, then figure out the axis of rotation, which is the cross
  169.  * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
  170.  * Note:  This is a deformed trackball-- is a trackball in the center,
  171.  * but is deformed into a hyperbolic solid of rotation away from the
  172.  * center.
  173.  * 
  174.  * It is assumed that the arguments to this routine are in the range
  175.  * (-1.0 ... 1.0)
  176.  */
  177. trackball(e,p1x,p1y,p2x,p2y)
  178. float e[4], p1x, p1y, p2x, p2y;
  179. {
  180.     vect a;    /* Axis of rotation */
  181.     float phi;    /* how much to rotate about axis */
  182.     vect p1, p2, d;
  183.  
  184.     if (p1x == p2x && p1y == p2y) {
  185.     vset4(e,0.0,0.0,0.0,1.0); /* Zero rotation */
  186.     return;
  187.     }
  188.  
  189. /*
  190.  * First, figure out z-coordinates for projection of P1 and P2 to
  191.  * deformed sphere
  192.  */
  193.     vset(&p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
  194.     vset(&p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
  195.  
  196. /*
  197.  *    Now, we want the cross product of P1 and P2
  198.  */
  199.     vcross(&p2,&p1,&a);
  200.  
  201. /*
  202.  *    Figure out how much to rotate around that axis.
  203.  */
  204.     vsub(&p1,&p2,&d);
  205.     phi = 2.0 * asin(vlength(&d) / (2.0*TRACKBALLSIZE));
  206.     axis_to_quat(&a,phi,e);
  207. }
  208.  
  209. /*
  210.  *    Given an axis and angle, compute quaternion.
  211.  */
  212. axis_to_quat(a,phi,e)
  213. vect *a;
  214. float phi, e[4];
  215. {
  216.     vnormal(a);
  217.     vcopy(a,e);
  218.     vscale(e,fsin(phi/2.0));
  219.     e[3] = fcos(phi/2.0);
  220. }
  221.  
  222. /*
  223.  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
  224.  * if we are away from the center of the sphere.
  225.  */
  226. float tb_project_to_sphere(r,x,y)
  227. float r, x, y;
  228. {
  229.     float d, t, z;
  230.  
  231.     d = fsqrt(x*x + y*y);
  232.     if (d < r*SQRT1_2)      /* Inside sphere */
  233.     z = fsqrt(r*r - d*d);
  234.     else {             /* On hyperbola */
  235.     t = r / SQRT2;
  236.     z = t*t / d;
  237.     }
  238.     return z;
  239. }
  240.  
  241. /*
  242.  * Given two rotations, e1 and e2, expressed as quaternion rotations,
  243.  * figure out the equivalent single rotation and stuff it into dest.
  244.  * 
  245.  * This routine also normalizes the result every RENORMCOUNT times it is
  246.  * called, to keep error from creeping in.
  247.  *
  248.  */
  249. add_quats(e1,e2,dest)
  250. float e1[4], e2[4], dest[4];
  251. {
  252.     static int count=0;
  253.     int i;
  254.     float t1[4], t2[4], t3[4];
  255.     float tf[4];
  256.  
  257.     vcopy(e1,t1); 
  258.     vscale(t1,e2[3]);
  259.  
  260.     vcopy(e2,t2); 
  261.     vscale(t2,e1[3]);
  262.  
  263.     vcross(e2,e1,t3);
  264.     vadd(t1,t2,tf);
  265.     vadd(t3,tf,tf);
  266.     tf[3] = e1[3] * e2[3] - vdot(e1,e2);
  267.  
  268.     dest[0] = tf[0];
  269.     dest[1] = tf[1];
  270.     dest[2] = tf[2];
  271.     dest[3] = tf[3];
  272.  
  273.     if (++count > RENORMCOUNT) {
  274.     count = 0;
  275.     normalize_quat(dest);
  276.     }
  277. }
  278.  
  279. /*
  280.  * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
  281.  * If they don't add up to 1.0, dividing by their magnitued will
  282.  * renormalize them.
  283.  *
  284.  * Note: See the following for more information on quaternions:
  285.  * 
  286.  * - Shoemake, K., Animating rotation with quaternion curves, Computer
  287.  *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
  288.  * - Pletinckx, D., Quaternion calculus as a basic tool in computer
  289.  *   graphics, The Visual Computer 5, 2-13, 1989.
  290.  */
  291. normalize_quat(e)
  292. float e[4];
  293. {
  294.     int i;
  295.     float mag;
  296.  
  297.     mag = (e[0]*e[0] + e[1]*e[1] + e[2]*e[2] + e[3]*e[3]);
  298.     for (i = 0; i < 4; i++) e[i] /= mag;
  299. }
  300.  
  301. /*
  302.  * Build a rotation matrix, given a quaternion rotation.
  303.  *
  304.  */
  305. build_rotmatrix(m,e)
  306. float m[4][4];
  307. float e[4];
  308. {
  309.     m[0][0] = 1.0 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
  310.     m[0][1] = 2.0 * (e[0] * e[1] - e[2] * e[3]);
  311.     m[0][2] = 2.0 * (e[2] * e[0] + e[1] * e[3]);
  312.     m[0][3] = 0.0;
  313.  
  314.     m[1][0] = 2.0 * (e[0] * e[1] + e[2] * e[3]);
  315.     m[1][1] = 1.0 - 2.0 * (e[2] * e[2] + e[0] * e[0]);
  316.     m[1][2] = 2.0 * (e[1] * e[2] - e[0] * e[3]);
  317.     m[1][3] = 0.0;
  318.  
  319.     m[2][0] = 2.0 * (e[2] * e[0] - e[1] * e[3]);
  320.     m[2][1] = 2.0 * (e[1] * e[2] + e[0] * e[3]);
  321.     m[2][2] = 1.0 - 2.0 * (e[1] * e[1] + e[0] * e[0]);
  322.     m[2][3] = 0.0;
  323.  
  324.     m[3][0] = 0.0;
  325.     m[3][1] = 0.0;
  326.     m[3][2] = 0.0;
  327.     m[3][3] = 1.0;
  328. }
  329.  
  330. vcopy3(a,b)
  331. float *a, *b;
  332. {
  333.     b[0] = a[0];
  334.     b[1] = a[1];
  335.     b[2] = a[2];
  336. }
  337.  
  338. static float   idmat[4][4] = {
  339.     1.0, 0.0, 0.0, 0.0,
  340.     0.0, 1.0, 0.0, 0.0,
  341.     0.0, 0.0, 1.0, 0.0,
  342.     0.0, 0.0, 0.0, 1.0
  343. };
  344.  
  345. myidentity()
  346. {
  347.     loadmatrix(idmat);
  348. }
  349.  
  350. matinit()
  351. {
  352.     mmode(MVIEWING); 
  353.     myidentity();
  354.     smartsetdepth();
  355. }
  356.